package org.example.csv;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

public class CSVData {

    private static final Logger LOG = LoggerFactory.getLogger(CSVData.class);

    private List<String> headers;

    private Map<String, Integer> headerMap;

    private List<String[]> lines;

    public CSVData() {
    }

    public CSVData(List<String> headers) {
        this.headers = headers;
    }

    public CSVData(List<String> headers, int cnt) {
        this.headers = headers;
        this.headerMap = new HashMap<>();
        for (int i = 0; i < headers.size(); i++) {
            this.headerMap.put(headers.get(i), i);
        }
        this.lines = new ArrayList<>(cnt);
    }

    public CSVData(List<String> headers, Map<String, Integer> headerMap) {
        this.headers = headers;
        this.headerMap = headerMap;
    }

    public CSVData(List<String> headers, List<String[]> lines) {
        this.headers = headers;
        this.lines = lines;
    }

    public CSVData(List<String> headers, Map<String, Integer> headerMap, List<String[]> lines) {
        this.headers = headers;
        this.headerMap = headerMap;
        this.lines = lines;
    }

    public List<String> getHeaders() {
        return headers;
    }

    public void setHeaders(List<String> headers) {
        this.headers = headers;
    }

    public Map<String, Integer> getHeaderMap() {
        return headerMap;
    }

    public void setHeaderMap(Map<String, Integer> headerMap) {
        this.headerMap = headerMap;
    }

    public List<String[]> getLines() {
        return lines;
    }

    public void setLines(List<String[]> lines) {
        this.lines = lines;
    }

    public void addLine(String[] line) {
        if (Objects.isNull(this.lines)) {
            this.lines = new ArrayList<>();
        }
        this.lines.add(line);
    }

    public void addLines(List<String[]> lines) {
        if (Objects.isNull(this.lines)) {
            this.lines = new ArrayList<>();
        }
        this.lines.addAll(lines);
    }

    public long count() {
        return this.lines.size();
    }

    public List<String> getByColumn(String columnName) {
        if (!this.headerMap.containsKey(columnName)) {
            LOG.error("Column {} not exist in csv.", columnName);
            throw new RuntimeException("Column not exist in csv");
        }
        int idx = this.headerMap.get(columnName);
        List<String> columnValues = new ArrayList<>();
        for (String[] line : this.lines) {
            columnValues.add(line[idx]);
        }
        return columnValues;
    }

    public List<String> getByColumn(int idx) {
        List<String> columnValues = new ArrayList<>((int) count());
        for (String[] line : this.lines) {
            columnValues.add(line[idx]);
        }
        return columnValues;
    }

    public Map<String, List<String>> getByColumns(List<String> columnNames) {
        Map<String, List<String>> colValuesMap = new HashMap<>();
        for (String columnName : columnNames) {
            List<String> column = getByColumn(columnName);
            colValuesMap.put(columnName, column);
        }
        return colValuesMap;
    }

    public boolean existField(String columnName) {
        return headerMap.containsKey(columnName);
    }

    public int getHeaderIndex(String columnName) {
        if (!existField(columnName)) {
            throw new RuntimeException("not exist column");
        }
        return this.headerMap.get(columnName);
    }

    public void sortValues() {
        if (Objects.isNull(this.lines)) {
            throw new RuntimeException("lines is empty");
        }
        this.lines.sort((o1, o2) -> {
            long idx1 = Long.parseLong(o1[0]);
            long idx2 = Long.parseLong(o2[0]);
            return Long.compare(idx1, idx2);
        });
    }

    @Override
    public String toString() {
        return "CSVData{" +
                "headers=" + headers +
                ", headerMap=" + headerMap +
                ", lines=" + lines +
                '}';
    }
}
